/**
 * @File Name: queue.c
 * @brief  
 * @Author : LiWanglin email:lwl510ll@163.com
 * @Version : 1.0
 * @Creat Date : 2023-07-18
 * 
 * @copyright Copyright (c) 2023 LiWanglin
 */

#include <queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

queue *queue_init(cm_uint16 buf_max_len, err_code *err)
{
    queue *q = (queue *)malloc(sizeof(queue));

    if(NULL == q) {
        *err = err_malloc_failed;
    }

    memset(q, 0, sizeof(queue));

    q->buf_max_len = buf_max_len;
    q->buf = (cm_uint8 *)malloc(sizeof(q->buf_max_len));
    if(NULL == q->buf) {
        free(q);
        q = NULL;
        *err = err_malloc_failed;
    }

    q->rear = 0;
    q->front = 0;

    return q;
}

queue *queue_uninit(queue *q)
{
    if(q != NULL) {
        if(NULL != q->buf) {
            free(q->buf);
            q->buf = NULL;
        }

        free(q);
        q = NULL;
    }

    return q;
}

/**
 * @brief  队列入队实现
 * @param  q: 
 * @param  data: 
 * @param  len: 
 * @return cm_uint16: 
 */
cm_int16 queue_en(queue *q, const cm_uint8 *data, cm_uint16 len)
{   
    if(NULL == q) {
        return err_point_null;
    }

    if(NULL == data) {
        return err_point_null;
    }

    cm_int16 temp_len = 0, leave = 0;

    if(q->rear >= q->front) {
        leave = q->buf_max_len - (q->rear - q->front);
        if(leave >= len) {
            leave = q->buf_max_len - q->rear;
            if(leave >= len) {
                memcpy(&q->buf[q->rear], data, len);
                q->rear += len;
                temp_len = len;
            } else {
                memcpy(&q->buf[q->rear], data, leave);
                temp_len = len - leave;
                memcpy(q->buf, &data[leave], temp_len);
                temp_len += leave;
                q->rear = leave;
            }
        } else {
            temp_len = len > q->buf_max_len ? q->buf_max_len : len;
            leave = q-> buf_max_len - q->rear;
            if(cm_true == q->coverage_flag) {
                memcpy(&q->buf[q->rear], data, leave);
                temp_len -= leave; 
                memcpy(q->buf, &data[leave], temp_len);
                q->front = q->rear;
                q->rear = leave;
                temp_len += leave;
            } else {
                memcpy(&q->buf[q->rear], data, leave);
                temp_len = (q->front-1) > 0 ? (q->front-1):0;
                if(temp_len > 0) {
                    memcpy(q->buf, &data[leave], temp_len);
                }
                temp_len += leave;
                q->rear = temp_len;
            }
        }
    } else {
       leave = q->front - q->rear;
       if(leave > len) {
           memcpy(&q->buf[q->rear], data, len);
           q->rear += len;
       } else {
           if(cm_true == q->coverage_flag) {
               temp_len = len > q->buf_max_len ? q->buf_max_len : len;
               if(temp_len > leave) {
                   memcpy(&q->buf[q->rear], data, leave);
                   leave -= temp_len;
                   memcpy(q->buf, &data[leave], leave);
                   q->front = q->rear;
                   q->rear = leave;
               }
           } else {
               memcpy(&q->buf[q->rear], data, leave);
               q->rear += leave;
               temp_len = leave;
           }
       }
    }

    return temp_len;
}

cm_int16 queue_de(queue *q, cm_uint8 *data, cm_uint16 len)
{
    if(q == NULL) {
        return err_point_null;
    }

    cm_int16 temp_len = 0;

    if(q->rear > q->front) {
        temp_len = q->rear - q->front;
        if(len >= temp_len) {
            memcpy(data, &q->buf[q->front], temp_len);
            q->front = q->rear;
        } else {
            memcpy(data, &q->buf[q->front], len);
            temp_len = len;
            q->front += len;
        }
    } else if(q->rear < q->front) {
        cm_int16 leave = q->buf_max_len - q->front;
        if(leave >= len) {
            memcpy(data, &q->buf[q->front], len);
            temp_len = len;
            q->front += len;
        } else {
            memcpy(data, &q->buf[q->front], leave);
            len -= leave;
            if(q->rear > len) {
                memcpy(&data[leave], &q->buf, len);
                q->front = len;
                temp_len = len+leave;
            } else {
                memcpy(&data[leave], &q->buf, q->rear);
                q->front = q->rear;
                temp_len = leave + q->rear;
            }
        }
    }

    return temp_len;
}

err_code queue_de_all(queue *q, cm_uint8 *data, cm_uint16 *len)
{
    if(q == NULL) {
        return err_point_null;
    }

    cm_int16 temp_len = 0;

    if(q->rear > q->front) {
        temp_len = q->rear - q->front;
        memcpy(data, &q->buf[q->front], temp_len);
    } else if(q->rear < q->front) {
        cm_int16 leave = q->buf_max_len - q->front;
        memcpy(data, &q->buf[q->front], leave);
        memcpy(&data[leave], q->buf, q->rear);
        temp_len = leave + q->rear;
    }

    q->front = 0;
    q->rear = 0;

    *len = temp_len;
    return err_ok;
}

cm_int16 queue_get_cur_len(queue *q)
{
    if(q == NULL) {
        return err_point_null;
    }

    cm_int16 len = 0;
    len = q->rear > q->front ? (q->rear - q->front) : (q->buf_max_len - q->front + q->rear);

    return len;
}

cm_int16 queue_get_max_len(queue *q)
{
    if(q == NULL) {
        return err_point_null;
    }

    return q->buf_max_len;
}


err_code queue_clear(queue *q)
{
    if(q == NULL) {
        return err_point_null;
    }

    q->rear = 0;
    q->front = 0;

    return err_ok;
}